package com.JUC;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 多线程编程的企业级 套路+模板
 * 1. 在高内聚低耦合的前提下，线程  操作（对外暴露的调用方法）  资源类（多个线程操作同一个资源类）
 */
//题目：三个售票员 卖出 30张票
public class JUC01_saleTicket01 {
    //main 一切程序的入口
    public static void main(String[] args) {
        //1.2 初始化资源类
        Ticket01 ticket = new Ticket01();


        //1.3 线程：有三个售票员就新建三个线程,三个线程操作同一个资源类
        //实际使用 Thread(Runnable target, String name) 新建进程
        //使用你们内部类，直接 new 一个 Runnable 接口对象


    /**复习 thread.start() : 执行这句话，线程不会马上启动，
         * 只是代表这个线程进入就绪态，
         * 只有当 操作系统 和 CPU 底层调用到线程中的 run 方法才表示线程启动*/

    /** 过于 冗长、太乱、太占地方，所以需要优化
        //进程 1
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 30; i++){
                    ticket.sale();
                }
            }
        },"Thread_A").start();



        //进程2
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 30; i++){
                    ticket.sale();
                }
            }
        },"Thread_B").start();
        //进程3
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 30; i++){
                    ticket.sale();
                }
            }
        },"Thread_C").start();
     */

    //使用  Lambda表达式 优化,不过为了思路不乱、清晰
        // 最好先用匿名内部类写个例子，再变换
        new Thread(()->{for (int i = 1; i <= 30; i++) ticket.sale();},"Thread_A").start();
        new Thread(()->{for (int i = 1; i <= 30; i++) ticket.sale();},"Thread_B").start();
        new Thread(()->{for (int i = 1; i <= 30; i++) ticket.sale();},"Thread_C").start();

    }
}
//对套路 1 的解释
//1.1 资源类
//需要做到高内聚，就要把对自己的操作的方法、把对外提供的功能放在自己身上

class Ticket01 {
    private int number = 30;
    //不使用 synchronized ，因为加上  synchronized 的方法总所有代码都会被加锁
    //改用 lock 接口及其实现类 ReentrantLock(可重入锁)，来优化
    private Lock lock = new ReentrantLock();

    //资源类，自带了对外提供的功能
    public void sale() {

        // lock 模块
        // 上锁
        lock.lock();
        try {

            //售票的业务逻辑
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + " 卖出第：" + (number--) + "票，还剩下：" + number + "张");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 开锁
            lock.unlock();
        }

    }
}